import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:moonmate/utils/errors.dart';
import 'dart:developer';

// 错误日志级别枚举
enum ErrorLogLevel {
  debug,
  info,
  warning,
  error,
  critical
}

// 错误上报器类型定义
typedef ErrorReporter = Future<void> Function(AppError error, String context);

class ErrorHandler {
  // 错误上报器
  ErrorReporter? _errorReporter;
  
  // 最大重试次数
  static const int maxRetries = 3;
  
  // 重试延迟时间（毫秒）
  static const Duration retryDelay = Duration(milliseconds: 500);
  
  // 重试条件回调
  bool Function(AppError error)? shouldRetry;
  
  // 重试前回调
  void Function(AppError error, int attempt)? onRetry;
  
  // 设置错误上报器
  void setErrorReporter(ErrorReporter reporter) {
    _errorReporter = reporter;
  }
  
  // 处理错误并返回AppError实例
  AppError handleError(dynamic error, [String context = '']) {
    log('Error in $context: $error');
    
    if (error is AppError) {
      _logError(error, context);
      _reportError(error, context);
      return error;
    }
    
    AppError appError;
    
    if (error is DatabaseException) {
      appError = createDatabaseError('数据库操作失败', cause: error);
    } else if (error is NetworkException) {
      appError = createNetworkError('网络连接失败', cause: error);
    } else if (error is TimeoutException) {
      appError = AppError.timeoutError('操作超时，请重试', cause: error);
    } else if (error is FormatException) {
      appError = AppError.parseError('数据格式错误', cause: error);
    } else if (error is StateError) {
      appError = AppError(
        message: '应用状态错误',
        type: AppErrorType.business,
        cause: error,
        stackTrace: StackTrace.current,
      );
    } else if (error is RangeError) {
      appError = AppError(
        message: '数据范围错误',
        type: AppErrorType.validation,
        cause: error,
        stackTrace: error.stackTrace ?? StackTrace.current,
      );
    } else if (error is TypeError) {
      appError = AppError(
        message: '类型错误',
        type: AppErrorType.parse,
        cause: error,
        stackTrace: error.stackTrace ?? StackTrace.current,
      );
    } else {
      appError = AppError.unknownError(cause: error);
    }
    
    _logError(appError, context);
    _reportError(appError, context);
    return appError;
  }
  
  // 安全操作封装
  Future<T> safeOperation<T>(
    Future<T> Function() operation,
    String operationName,
    {T Function()? fallbackValue,
    bool rethrowError = false,
    AppError Function(dynamic error)? onError}
  ) async {
    int attempts = 0;
    AppError? lastError;
    
    while (attempts < maxRetries) {
      try {
        attempts++;
        return await operation();
      } catch (e) {
        final AppError appError;
        
        if (onError != null) {
          appError = onError(e);
        } else {
          appError = handleError(e, '$operationName (attempt $attempts/$maxRetries)');
        }
        
        lastError = appError;
        
        // 检查是否应该重试
        final canRetry = attempts < maxRetries && 
                        (shouldRetry?.call(appError) ?? 
                         appError.isRecoverable || 
                         appError.type == AppErrorType.network ||
                         appError.type == AppErrorType.database ||
                         appError.type == AppErrorType.timeout);
        
        if (canRetry) {
          // 调用重试回调
          onRetry?.call(appError, attempts);
          
          // 等待重试延迟
          await Future.delayed(retryDelay * (attempts)); // 指数退避
          continue;
        }
        
        // 无后备值且不应重试，抛出错误
        if (fallbackValue == null) {
          throw appError;
        }
        
        // 使用后备值
        break;
      }
    }
    
    // 使用后备值
    if (fallbackValue != null) {
      final fallback = fallbackValue();
      log('Operation $operationName failed after $attempts attempts, using fallback value: $fallback');
      return fallback;
    }
    
    // 所有尝试都失败且没有后备值，抛出最后一个错误
    throw lastError ?? AppError.unknownError();
  }
  
  // 创建数据库错误
  AppError createDatabaseError(String message, {dynamic cause}) {
    return AppError.databaseError(message, cause: cause)
        .copyWith(stackTrace: StackTrace.current);
  }
  
  // 创建网络错误
  AppError createNetworkError(String message, {dynamic cause}) {
    return AppError(
      message: message,
      type: AppErrorType.network,
      cause: cause,
      isRecoverable: true,
      stackTrace: StackTrace.current,
    );
  }
  
  // 创建验证错误
  AppError createValidationError(String message, {dynamic cause}) {
    return AppError.validationError(message).copyWith(stackTrace: StackTrace.current);
  }
  
  // 创建存储错误
  AppError createStorageError(String message, {dynamic cause}) {
    return AppError(
      message: message,
      type: AppErrorType.storage,
      cause: cause,
      isRecoverable: false,
      stackTrace: StackTrace.current,
    );
  }
  
  // 创建业务错误
  AppError createBusinessError(String message, {dynamic cause}) {
    return AppError(
      message: message,
      type: AppErrorType.business,
      cause: cause,
      isRecoverable: true,
      stackTrace: StackTrace.current,
    );
  }
  
  // 创建数据损坏错误
  AppError createDataCorruptionError(String message, {dynamic cause}) {
    return AppError.fileError(message, cause: cause);
  }
  
  // 获取日志级别
  ErrorLogLevel _getLogLevel(AppErrorType type) {
    switch (type) {
      case AppErrorType.database:
      case AppErrorType.network:
        return ErrorLogLevel.error;
      case AppErrorType.validation:
      case AppErrorType.parse:
      case AppErrorType.timeout:
      case AppErrorType.business:
      case AppErrorType.storage:
        return ErrorLogLevel.warning;
      case AppErrorType.unknown:
      case AppErrorType.dataCorruption:
      case AppErrorType.permission:
      case AppErrorType.conflict:
      case AppErrorType.migration:
        return ErrorLogLevel.critical;
    }
  }
  
  // 获取用户友好的错误消息
  String getUserFriendlyMessage(AppError error) {
    // 根据不同错误类型提供更友好的消息
    switch (error.type) {
      case AppErrorType.database:
        return error.message.isNotEmpty ? error.message : '数据存储发生错误，请稍后重试';
      case AppErrorType.network:
        return error.message.isNotEmpty ? error.message : '网络连接失败，请检查网络设置';
      case AppErrorType.validation:
        return error.message.isNotEmpty ? error.message : '输入数据有误，请检查';
      case AppErrorType.parse:
        return error.message.isNotEmpty ? error.message : '数据解析错误，请更新应用';
      case AppErrorType.timeout:
        return error.message.isNotEmpty ? error.message : '操作超时，请重试';
      case AppErrorType.business:
        return error.message.isNotEmpty ? error.message : '操作无法完成，请稍后再试';
      case AppErrorType.storage:
        return error.message.isNotEmpty ? error.message : '存储空间不足，请清理后重试';
      case AppErrorType.permission:
        return error.message.isNotEmpty ? error.message : '需要相应权限才能完成操作';
      case AppErrorType.dataCorruption:
        return error.message.isNotEmpty ? error.message : '数据已损坏，请重新安装应用';
      case AppErrorType.unknown:
      default:
          // 对于未知错误，不展示技术细节，提供通用提示
          if (kReleaseMode) {
            return '抱歉，应用遇到未知错误，请重启应用后重试';
          } else {
            return error.message.isNotEmpty ? error.message : '发生未知错误';
          }
    }
  }
  
  // 显示错误对话框
  void showErrorDialog(BuildContext context, AppError error) {
    
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          backgroundColor: Colors.white,
          title: Text('操作失败', style: TextStyle(
            fontWeight: FontWeight.bold,
            fontSize: 18,
            color: Colors.red,
          )),
          content: Text(getUserFriendlyMessage(error)),
          actions: [
            TextButton(
              child: const Text('取消'),
              onPressed: () => Navigator.of(context).pop(),
            ),
            if (error.isRecoverable || error.retryCallback != null) 
              TextButton(
                child: const Text('重试'),
                onPressed: () {
                  Navigator.of(context).pop();
                  if (error.retryCallback != null) {
                    error.retryCallback!();
                  }
                },
              ),
          ],
        );
      },
    );
  }
  
  // 显示SnackBar错误提示
  void showErrorSnackBar(BuildContext context, AppError error, {Duration duration = const Duration(seconds: 3)}) {
    final snackBar = SnackBar(
      content: Text(getUserFriendlyMessage(error)),
      duration: duration,
      backgroundColor: Colors.red[600],
      action: error.isRecoverable || error.retryCallback != null
          ? SnackBarAction(
              label: '重试',
              onPressed: () {
                if (error.retryCallback != null) {
                  error.retryCallback!();
                }
              },
            )
          : null,
    );
    
    ScaffoldMessenger.of(context).showSnackBar(snackBar);
  }
  
  // 记录错误日志
  void _logError(AppError error, String context) {
    final level = _getLogLevel(error.type);
    
    if (kDebugMode) {
      switch (level) {
        case ErrorLogLevel.debug:
          log('[$context] Debug Error: ${error.message}', level: 0);
          break;
        case ErrorLogLevel.info:
          log('[$context] Info Error: ${error.message}', level: 1);
          break;
        case ErrorLogLevel.warning:
          log('[$context] Warning Error: ${error.message}', level: 2);
          break;
        case ErrorLogLevel.error:
          log('[$context] Error: ${error.message}', 
              error: error.cause,
              stackTrace: error.stackTrace,
              level: 3);
          break;
        case ErrorLogLevel.critical:
          log('[$context] CRITICAL ERROR: ${error.message}', 
              error: error.cause,
              stackTrace: error.stackTrace,
              level: 9);
          break;
      }
    }
  }
  
  // 上报错误（异步）
  Future<void> _reportError(AppError error, String context) async {
    if (_errorReporter != null) {
      try {
        await _errorReporter!(error, context);
      } catch (e) {
        // 错误上报失败不影响应用流程
        log('Error reporting failed: $e');
      }
    }
  }
  
  // 同步执行安全操作
  T safeSyncOperation<T>(
    T Function() operation,
    String operationName,
    {T Function()? fallbackValue,
    AppError Function(dynamic error)? onError}
  ) {
    try {
      return operation();
    } catch (e) {
      AppError? appError;
      
      if (onError != null) {
        appError = onError(e);
      } else {
        appError = handleError(e, operationName);
      }
      
      _logError(appError, operationName);
      
      if (fallbackValue != null) {
        final fallback = fallbackValue();
        log('Sync operation $operationName failed, using fallback value: $fallback');
        return fallback;
      }
      
      throw appError;
    }
  }
  
  // 批量安全操作
  Future<List<T>> safeBatchOperation<T>(
    List<Future<T> Function()> operations,
    String operationName,
    {bool continueOnError = false}
  ) async {
    final results = <T>[];
    final errors = <int, AppError>{};
    
    for (int i = 0; i < operations.length; i++) {
      try {
        final result = await safeOperation(
          operations[i],
          '$operationName (item $i)',
        );
        results.add(result);
      } catch (e) {
        if (e is AppError) {
          errors[i] = e;
          
          if (continueOnError) {
            // 继续执行下一个操作
            continue;
          } else {
            throw AppError(
              message: '批量操作失败，在第 ${i+1} 项出错',
              type: AppErrorType.business,
              cause: e,
              stackTrace: StackTrace.current,
            );
          }
        } else {
          rethrow;
        }
      }
    }
    
    // 如果有错误但设置了继续执行，则返回结果并记录错误
    if (errors.isNotEmpty) {
      _logError(
        AppError(
          message: '批量操作完成，但有 ${errors.length} 项失败',
          type: AppErrorType.business,
          cause: errors,
          stackTrace: StackTrace.current,
        ),
        operationName,
      );
    }
    
    return results;
  }
}

// 数据库异常类
base class DatabaseException implements Exception {
  final String message;
  final dynamic originalError;
  final String? operation;
  
  DatabaseException(this.message, {this.originalError, this.operation});
  
  @override
  String toString() {
    final opStr = operation != null ? ' [Operation: $operation]' : '';
    return 'DatabaseException: $message$opStr';
  }
}

// 网络异常类
base class NetworkException implements Exception {
  final String message;
  final dynamic originalError;
  final int? statusCode;
  final String? url;
  
  NetworkException(this.message, {this.originalError, this.statusCode, this.url});
  
  @override
  String toString() {
    final urlStr = url != null ? ' [URL: $url]' : '';
    final statusStr = statusCode != null ? ' (Status: $statusCode)' : '';
    return 'NetworkException: $message$statusStr$urlStr';
  }
}

// 验证异常类
base class ValidationException implements Exception {
  final String message;
  final String? field;
  final dynamic value;
  
  ValidationException(this.message, {this.field, this.value});
  
  @override
  String toString() {
    final fieldStr = field != null ? ' [Field: $field]' : '';
    final valueStr = value != null ? ' [Value: $value]' : '';
    return 'ValidationException: $message$fieldStr$valueStr';
  }
}

// 存储异常类
base class StorageException implements Exception {
  final String message;
  final String? path;
  final dynamic originalError;
  
  StorageException(this.message, {this.path, this.originalError});
  
  @override
  String toString() {
    final pathStr = path != null ? ' [Path: $path]' : '';
    return 'StorageException: $message$pathStr';
  }
}

// 业务规则异常类
base class BusinessRuleException implements Exception {
  final String message;
  final String? rule;
  
  BusinessRuleException(this.message, {this.rule});
  
  @override
  String toString() {
    final ruleStr = rule != null ? ' [Rule: $rule]' : '';
    return 'BusinessRuleException: $message$ruleStr';
  }
}

// 超时异常类
base class TimeoutException implements Exception {
  final String message;
  final Duration? timeout;
  
  TimeoutException(this.message, {this.timeout});
  
  @override
  String toString() => 'TimeoutException: $message${timeout != null ? ' (after $timeout)' : ''}';
}
